package cn.tedu.tmall.admin.content.configuration;

import cn.tedu.tmall.admin.content.filter.JwtAuthorizationFilter;
import cn.tedu.tmall.common.ServiceCodeEnum;
import cn.tedu.tmall.common.web.JsonResult;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import java.io.PrintWriter;

/**
 * Spring Security的配置类（适配Spring Security 6.x）
 *
 * @author java@tedu.cn
 * @version 3.5.5
 */
@Slf4j
@Configuration
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration {

    @Autowired
    private JwtAuthorizationFilter jwtAuthorizationFilter;

    @Autowired
    private AuthenticationConfiguration authenticationConfiguration;

    public SecurityConfiguration() {
        log.debug("创建配置类对象：SecurityConfiguration");
    }

    /**
     * 密码编码器
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 认证管理器
     */
    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    /**
     * 安全过滤器链（核心配置）
     */
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // 1. 配置Session为无状态
        http.sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        );

        // 2. 添加JWT过滤器
        http.addFilterBefore(jwtAuthorizationFilter, UsernamePasswordAuthenticationFilter.class);

        // 3. 跨域配置
        http.cors(cors -> cors
                .configurationSource(request -> {
                    org.springframework.web.cors.CorsConfiguration config = new org.springframework.web.cors.CorsConfiguration();
                    config.applyPermitDefaultValues();
                    return config;
                })
        );

        // 4. 未登录访问处理
        http.exceptionHandling(exception -> exception
                .authenticationEntryPoint((request, response, e) -> {
                    log.warn("未认证访问受保护资源：", e);
                    response.setContentType("application/json; charset=utf-8");
                    String message = "操作失败，您当前未登录！";
                    JsonResult jsonResult = JsonResult.fail(ServiceCodeEnum.ERROR.getCode(), message);
                    PrintWriter writer = response.getWriter();
                    writer.println(JSON.toJSONString(jsonResult));
                    writer.close();
                })
        );

        // 5. 白名单路径
        String[] urls = {
                "/favicon.ico",
                "/doc.html",
                "/**/*.css",
                "/**/*.js",
                "/swagger-resources/**",
                "/v2/api-docs/**",
                "/v3/api-docs/**",
                "/swagger-ui/**"
        };

        // 6. 禁用CSRF
        http.csrf(csrf -> csrf.disable());

        // 7. 请求授权配置（改用Ant风格路径匹配，直接匹配白名单）
        http.authorizeHttpRequests(authorize -> authorize
                .requestMatchers(urls)
                .permitAll()
                .anyRequest()
                .authenticated()
        );

        return http.build();
    }

}
